package org.huangrui.juc.source.lockSupport;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author hr
 * @Create 2024-04-02 13:05
 */
public class T01_LockSupport {
    public static void main(String[] args) {
        // syncWaitNotify();
        // lockAwaitSignal();
        lockSupportPark();
    }

    private static void lockSupportPark() {
        Thread t1 = new Thread(() -> {
            //暂停1秒钟
            try { TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}
            System.out.println(Thread.currentThread().getName()+"\t -----come in " +System.currentTimeMillis());
            LockSupport.park();
            // LockSupport.park(); // 与信号量不同 但是，许可证不会累积。最多有一个
            System.out.println(Thread.currentThread().getName()+"\t -----被唤醒了 " +System.currentTimeMillis());
        }, "t1");
        t1.start();

        new Thread(() ->{
            LockSupport.unpark(t1);
            LockSupport.unpark(t1);
            System.out.println(Thread.currentThread().getName()+"\t -- 发出通知 in " +System.currentTimeMillis());
        },"t2").start();
    }

    /**
     异常1：condition.await();和condition.signal();都触发了IllegalMonitorStateException异常
     * 原因：调用condition中线程等待和唤醒的方法的前提是，要在lock和unlock方法中,要有锁才能调用
     *
     * 异常2：阻塞线程无法被唤醒
     * 原因：先await()后signal才OK，否则线程无法被唤醒
     */
    private static void lockAwaitSignal() {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        new Thread(() ->{
            //暂停100毫秒
            try { TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
           lock.lock();
           try {
                System.out.println(Thread.currentThread().getName()+"\t -----come in");
                condition.await();
               System.out.println(Thread.currentThread().getName()+"\t -----被唤醒了");
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           } finally {
               lock.unlock();
           }
        },"t1").start();

        new Thread(() ->{
           lock.lock();
           try {
               condition.signal();
               System.out.println(Thread.currentThread().getName()+"\t -- 发出通知 in");
           }catch (Exception e){
               e.printStackTrace();
           }finally {
               lock.unlock();
           }
        },"t2").start();
    }

    /**
     * 以下异常情况：
     *  2 wait方法和notify方法，两个都去掉同步代码块后看运行效果
     *    2.1 异常情况
     *    Exception in thread "t1" java.lang.IllegalMonitorStateException at java.lang.Object.wait(Native Method)
     *    Exception in thread "t2" java.lang.IllegalMonitorStateException at java.lang.Object.notify(Native Method)
     *    2.2 结论
     *    Object类中的wait、notify、notifyAll用于线程等待和唤醒的方法，都必须在synchronized内部执行（必须用到关键字synchronized）。
     *
     * 3 将notify放在wait方法前先执行，t2先notify了，3秒钟后t1线程再执行wait方法
     *   3.1 程序一直无法结束
     *   3.2 结论
     *   先wait后notify、notifyall方法，等待中的线程才会被唤醒，否则无法唤醒
     */
    private static void syncWaitNotify() {
        Object objectLock = new Object();
        new Thread(() ->{
           //暂停200毫秒
           // try { TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
           synchronized (objectLock){
                System.out.println(Thread.currentThread().getName()+"\t -----come in");
               try {
                   objectLock.wait();
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
                System.out.println(Thread.currentThread().getName()+"\t -----被唤醒了");
           }
        },"t1").start();

        new Thread(() ->{
           synchronized (objectLock){
               objectLock.notify();
               System.out.println(Thread.currentThread().getName()+"\t -- 发出通知 in");
           }
        },"t2").start();
    }
}
